Sensor Fusion for Kinetis MCUs (ISSDK/KSDK version)
precisionAccelerometer.h File Reference
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  AccelBuffer
 
struct  AccelCalibration
 

Macros

#define ACCEL_CAL_AVERAGING_SECS   2
 
#define MAX_ACCEL_CAL_ORIENTATIONS   12
 

Typedefs

typedef struct AccelBuffer AccelBuffer
 
typedef struct AccelCalibration AccelCalibration
 

Functions

void fInitializeAccelCalibration (struct AccelCalibration *pthisAccelCal, struct AccelBuffer *pthisAccelBuffer, volatile int8_t *AccelCalPacketOn)
 
void fUpdateAccelBuffer (struct AccelCalibration *pthisAccelCal, struct AccelBuffer *pthisAccelBuffer, struct AccelSensor *pthisAccel, volatile int8_t *AccelCalPacketOn)
 
void fInvertAccelCal (struct AccelSensor *pthisAccel, struct AccelCalibration *pthisAccelCal)
 
void fRunAccelCalibration (struct AccelCalibration *pthisAccelCal, struct AccelBuffer *pthisAccelBuffer, struct AccelSensor *pthisAccel)
 
void fComputeAccelCalibration4 (struct AccelBuffer *pthisAccelBuffer, struct AccelCalibration *pthisAccelCal, struct AccelSensor *pthisAccel)
 
void fComputeAccelCalibration7 (struct AccelBuffer *pthisAccelBuffer, struct AccelCalibration *pthisAccelCal, struct AccelSensor *pthisAccel)
 
void fComputeAccelCalibration10 (struct AccelBuffer *pthisAccelBuffer, struct AccelCalibration *pthisAccelCal, struct AccelSensor *pthisAccel)
 

Macro Definition Documentation

#define ACCEL_CAL_AVERAGING_SECS   2

calibration constants

calibration measurement averaging period (s)

Definition at line 34 of file precisionAccelerometer.h.

Referenced by DecodeCommandBytes(), and fUpdateAccelBuffer().

#define MAX_ACCEL_CAL_ORIENTATIONS   12

Typedef Documentation

typedef struct AccelBuffer AccelBuffer

accelerometer measurement buffer

precision accelerometer calibration structure

Function Documentation

void fComputeAccelCalibration10 ( struct AccelBuffer pthisAccelBuffer,
struct AccelCalibration pthisAccelCal,
struct AccelSensor pthisAccel 
)

calculate the 10 element calibration from the available measurements

Parameters
pthisAccelBufferBuffer of measurements used as input to the accel calibration functions
pthisAccelCalAccelerometer calibration parameter structure
pthisAccelPointer to the accelerometer input/state structure

Definition at line 442 of file precisionAccelerometer.c.

Referenced by fRunAccelCalibration().

445 {
446  int32 i,
447  j,
448  k,
449  l,
450  m,
451  n; // loop counters
452  float det; // matrix determinant
453  float ftmp; // scratch
454  float fg0; // fitted local gravity magnitude
455 
456  // zero the on and above diagonal elements of the 10x10 symmetric measurement matrix fmatA
457  for (i = 0; i < 10; i++)
458  for (j = i; j < 10; j++) pthisAccelCal->fmatA[i][j] = 0.0F;
459 
460  // last entry of vector fvecA is always 1.0 so move assignment outside the loop
461  pthisAccelCal->fvecA[9] = 1.0F;
462 
463  // loop over all orientations
464  for (i = 0; i < MAX_ACCEL_CAL_ORIENTATIONS; i++)
465  {
466  // accumulate fvecA if this entry is valid
467  if ((pthisAccelBuffer->iStoreFlags) & (1 << i))
468  {
469  // compute the remaining members of the measurement vector fvecA
470  pthisAccelCal->fvecA[6] = pthisAccelBuffer->fGsStored[i][CHX];
471  pthisAccelCal->fvecA[7] = pthisAccelBuffer->fGsStored[i][CHY];
472  pthisAccelCal->fvecA[8] = pthisAccelBuffer->fGsStored[i][CHZ];
473  pthisAccelCal->fvecA[0] = pthisAccelCal->fvecA[6] * pthisAccelCal->fvecA[6];
474  pthisAccelCal->fvecA[1] = 2.0F *
475  pthisAccelCal->fvecA[6] *
476  pthisAccelCal->fvecA[7];
477  pthisAccelCal->fvecA[2] = 2.0F *
478  pthisAccelCal->fvecA[6] *
479  pthisAccelCal->fvecA[8];
480  pthisAccelCal->fvecA[3] = pthisAccelCal->fvecA[7] * pthisAccelCal->fvecA[7];
481  pthisAccelCal->fvecA[4] = 2.0F *
482  pthisAccelCal->fvecA[7] *
483  pthisAccelCal->fvecA[8];
484  pthisAccelCal->fvecA[5] = pthisAccelCal->fvecA[8] * pthisAccelCal->fvecA[8];
485 
486  // accumulate the on-and above-diagonal terms of fmatA=Sigma{fvecA^T * fvecA}
487  for (m = 0; m < 10; m++)
488  {
489  for (n = m; n < 10; n++)
490  {
491  pthisAccelCal->fmatA[m][n] += pthisAccelCal->fvecA[m] * pthisAccelCal->fvecA[n];
492  }
493  }
494  } // end of test for stored data
495  } // end of loop over orientations
496 
497  // copy the above diagonal elements of symmetric product matrix fmatA to below the diagonal
498  for (m = 1; m < 10; m++)
499  for (n = 0; n < m; n++)
500  pthisAccelCal->fmatA[m][n] = pthisAccelCal->fmatA[n][m];
501 
502  // set fvecA to the unsorted eigenvalues and fmatB to the unsorted normalized eigenvectors of fmatA
503  fEigenCompute10(pthisAccelCal->fmatA, pthisAccelCal->fvecA,
504  pthisAccelCal->fmatB, 10);
505 
506  // set ellipsoid matrix A from elements of the solution vector column j with smallest eigenvalue
507  j = 0;
508  for (i = 1; i < 10; i++)
509  {
510  if (pthisAccelCal->fvecA[i] < pthisAccelCal->fvecA[j])
511  {
512  j = i;
513  }
514  }
515 
516  pthisAccelCal->fA[0][0] = pthisAccelCal->fmatB[0][j];
517  pthisAccelCal->fA[0][1] = pthisAccelCal->fA[1][0] = pthisAccelCal->fmatB[1][j];
518  pthisAccelCal->fA[0][2] = pthisAccelCal->fA[2][0] = pthisAccelCal->fmatB[2][j];
519  pthisAccelCal->fA[1][1] = pthisAccelCal->fmatB[3][j];
520  pthisAccelCal->fA[1][2] = pthisAccelCal->fA[2][1] = pthisAccelCal->fmatB[4][j];
521  pthisAccelCal->fA[2][2] = pthisAccelCal->fmatB[5][j];
522 
523  // negate entire solution if A has negative determinant
524  det = f3x3matrixDetA(pthisAccelCal->fA);
525  if (det < 0.0F)
526  {
527  f3x3matrixAeqMinusA(pthisAccelCal->fA);
528  pthisAccelCal->fmatB[6][j] = -pthisAccelCal->fmatB[6][j];
529  pthisAccelCal->fmatB[7][j] = -pthisAccelCal->fmatB[7][j];
530  pthisAccelCal->fmatB[8][j] = -pthisAccelCal->fmatB[8][j];
531  pthisAccelCal->fmatB[9][j] = -pthisAccelCal->fmatB[9][j];
532  det = -det;
533  }
534 
535  // compute the inverse of the ellipsoid matrix
536  f3x3matrixAeqInvSymB(pthisAccelCal->finvA, pthisAccelCal->fA);
537 
538  // compute the offset vector V
539  for (l = CHX; l <= CHZ; l++)
540  {
541  pthisAccelCal->fV[l] = 0.0F;
542  for (m = CHX; m <= CHZ; m++)
543  {
544  pthisAccelCal->fV[l] += pthisAccelCal->finvA[l][m] * pthisAccelCal->fmatB[m + 6][j];
545  }
546 
547  pthisAccelCal->fV[l] *= -0.5F;
548  }
549 
550  // compute the local gravity fit to these calibration coefficients
551  fg0 = sqrtf(fabsf(pthisAccelCal->fA[0][0] * pthisAccelCal->fV[CHX] *
552  pthisAccelCal->fV[CHX] + 2.0F * pthisAccelCal->fA[0][1] *
553  pthisAccelCal->fV[CHX] * pthisAccelCal->fV[CHY] + 2.0F *
554  pthisAccelCal->fA[0][2] * pthisAccelCal->fV[CHX] *
555  pthisAccelCal->fV[CHZ] + pthisAccelCal->fA[1][1] *
556  pthisAccelCal->fV[CHY] * pthisAccelCal->fV[CHY] + 2.0F *
557  pthisAccelCal->fA[1][2] * pthisAccelCal->fV[CHY] *
558  pthisAccelCal->fV[CHZ] + pthisAccelCal->fA[2][2] *
559  pthisAccelCal->fV[CHZ] * pthisAccelCal->fV[CHZ] -
560  pthisAccelCal->fmatB[9][j]));
561 
562  // compute trial invW from the square root of fA
563  // set fvecA to the unsorted eigenvalues and fmatB to the unsorted eigenvectors of fmatA
564  // where fmatA holds the 3x3 matrix fA in its top left elements
565  for (i = 0; i < 3; i++)
566  for (j = 0; j < 3; j++)
567  pthisAccelCal->fmatA[i][j] = pthisAccelCal->fA[i][j];
568  fEigenCompute10(pthisAccelCal->fmatA, pthisAccelCal->fvecA,
569  pthisAccelCal->fmatB, 3);
570 
571  // set fmatB to be eigenvectors . diag(sqrt(sqrt(eigenvalues))) = fmatB . diag(sqrt(sqrt(fvecA))
572  for (j = 0; j < 3; j++) // loop over columns j
573  {
574  ftmp = sqrtf(sqrtf(fabsf(pthisAccelCal->fvecA[j])));
575  for (i = 0; i < 3; i++) // loop over rows i
576  {
577  pthisAccelCal->fmatB[i][j] *= ftmp;
578  }
579  }
580 
581  // set finvW to eigenvectors * diag(sqrt(eigenvalues)) * eigenvectors^T
582  // = fmatB * fmatB^T = sqrt(fA) (guaranteed symmetric)
583  // loop over rows
584  for (i = 0; i < 3; i++)
585  {
586  // loop over on and above diagonal columns
587  for (j = i; j < 3; j++)
588  {
589  pthisAccelCal->finvW[i][j] = 0.0F;
590 
591  // accumulate the matrix product
592  for (k = 0; k < 3; k++)
593  {
594  pthisAccelCal->finvW[i][j] += pthisAccelCal->fmatB[i][k] * pthisAccelCal->fmatB[j][k];
595  }
596 
597  // copy to below diagonal element
598  pthisAccelCal->finvW[j][i] = pthisAccelCal->finvW[i][j];
599  }
600  }
601 
602  // scale finvW so that the calibrated measurements fit on the 1g sphere
603  for (i = CHX; i <= CHZ; i++)
604  {
605  for (j = CHX; j <= CHZ; j++)
606  {
607  pthisAccelCal->finvW[i][j] /= fg0;
608  }
609  }
610 
611  return;
612 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fvecA[10]
scratch 10x1 vector used by calibration algorithms
float fGsStored[MAX_ACCEL_CAL_ORIENTATIONS][3]
uncalibrated accelerometer measurements (g)
float fV[3]
offset vector (g)
void f3x3matrixAeqMinusA(float A[][3])
function negates all elements of 3x3 matrix A
Definition: matrix.c:147
int16_t iStoreFlags
denotes which measurements are present
float f3x3matrixDetA(float A[][3])
function calculates the determinant of a 3x3 matrix
Definition: matrix.c:209
int32_t int32
Definition: sensor_fusion.h:57
void fEigenCompute10(float A[][10], float eigval[], float eigvec[][10], int8 n)
function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1] stored in the top left of a 10x10 array A[10][10]
Definition: matrix.c:234
#define CHZ
void f3x3matrixAeqInvSymB(float A[][3], float B[][3])
function directly calculates the symmetric inverse of a symmetric 3x3 matrix only the on and above di...
Definition: matrix.c:168
float finvA[3][3]
inverse of the ellipsoid matrix A
#define MAX_ACCEL_CAL_ORIENTATIONS
number of stored precision accelerometer measurements
float fmatA[10][10]
scratch 10x10 matrix used by calibration algorithms
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float fmatB[10][10]
scratch 10x10 matrix used by calibration algorithms
float finvW[3][3]
inverse gain matrix
float fA[3][3]
ellipsoid matrix A

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fComputeAccelCalibration4 ( struct AccelBuffer pthisAccelBuffer,
struct AccelCalibration pthisAccelCal,
struct AccelSensor pthisAccel 
)

calculate the 4 element calibration from the available measurements

Parameters
pthisAccelBufferBuffer of measurements used as input to the accel calibration functions
pthisAccelCalAccelerometer calibration parameter structure
pthisAccelPointer to the accelerometer input/state structure

Definition at line 233 of file precisionAccelerometer.c.

Referenced by fRunAccelCalibration().

236 {
237  int32 i,
238  j; // loop counters
239  float ftmp; // scratch
240  int8_t ierror; // flag from matrix inversion
241 
242  // working arrays for 4x4 matrix inversion
243  float *pfRows[4];
244  int8_t iColInd[4];
245  int8_t iRowInd[4];
246  int8_t iPivot[4];
247 
248  // zero the 4x4 matrix XTX (in upper left of fmatA) and 4x1 vector XTY (in upper fvecA)
249  for (i = 0; i < 4; i++)
250  {
251  pthisAccelCal->fvecA[i] = 0.0F;
252  for (j = 0; j < 4; j++)
253  {
254  pthisAccelCal->fmatA[i][j] = 0.0F;
255  }
256  }
257 
258  // accumulate fXTY (in fvecA) and fXTX4x4 (in fmatA)
259  for (i = 0; i < MAX_ACCEL_CAL_ORIENTATIONS; i++)
260  {
261  // accumulate vector X^T.Y if this entry is valid
262  if ((pthisAccelBuffer->iStoreFlags) & (1 << i))
263  {
264  ftmp = pthisAccelBuffer->fGsStored[i][CHX] *
265  pthisAccelBuffer->fGsStored[i][CHX] +
266  pthisAccelBuffer->fGsStored[i][CHY] *
267  pthisAccelBuffer->fGsStored[i][CHY] +
268  pthisAccelBuffer->fGsStored[i][CHZ] *
269  pthisAccelBuffer->fGsStored[i][CHZ];
270  pthisAccelCal->fvecA[0] += pthisAccelBuffer->fGsStored[i][CHX] * ftmp;
271  pthisAccelCal->fvecA[1] += pthisAccelBuffer->fGsStored[i][CHY] * ftmp;
272  pthisAccelCal->fvecA[2] += pthisAccelBuffer->fGsStored[i][CHZ] * ftmp;
273  pthisAccelCal->fvecA[3] += ftmp;
274 
275  // accumulate above diagonal terms of matrix X^T.X
276  pthisAccelCal->fmatA[CHX][CHX] += pthisAccelBuffer->fGsStored[i][
277  CHX] *
278  pthisAccelBuffer->fGsStored[i][CHX];
279  pthisAccelCal->fmatA[CHX][CHY] += pthisAccelBuffer->fGsStored[i][
280  CHX] *
281  pthisAccelBuffer->fGsStored[i][CHY];
282  pthisAccelCal->fmatA[CHX][CHZ] += pthisAccelBuffer->fGsStored[i][
283  CHX] *
284  pthisAccelBuffer->fGsStored[i][CHZ];
285  pthisAccelCal->fmatA[CHX][3] += pthisAccelBuffer->fGsStored[i][CHX];
286  pthisAccelCal->fmatA[CHY][CHY] += pthisAccelBuffer->fGsStored[i][
287  CHY] *
288  pthisAccelBuffer->fGsStored[i][CHY];
289  pthisAccelCal->fmatA[CHY][CHZ] += pthisAccelBuffer->fGsStored[i][
290  CHY] *
291  pthisAccelBuffer->fGsStored[i][CHZ];;
292  pthisAccelCal->fmatA[CHY][3] += pthisAccelBuffer->fGsStored[i][CHY];
293  pthisAccelCal->fmatA[CHZ][CHZ] += pthisAccelBuffer->fGsStored[i][
294  CHZ] *
295  pthisAccelBuffer->fGsStored[i][CHZ];;
296  pthisAccelCal->fmatA[CHZ][3] += pthisAccelBuffer->fGsStored[i][CHZ];
297  pthisAccelCal->fmatA[3][3] += 1.0F;
298  }
299  }
300 
301  // copy above diagonal elements of fXTX4x4 = X^T.X to below diagonal elements
302  pthisAccelCal->fmatA[CHY][CHX] = pthisAccelCal->fmatA[CHX][CHY];
303  pthisAccelCal->fmatA[CHZ][CHX] = pthisAccelCal->fmatA[CHX][CHZ];
304  pthisAccelCal->fmatA[CHZ][CHY] = pthisAccelCal->fmatA[CHY][CHZ];
305  pthisAccelCal->fmatA[3][CHX] = pthisAccelCal->fmatA[CHX][3];
306  pthisAccelCal->fmatA[3][CHY] = pthisAccelCal->fmatA[CHY][3];
307  pthisAccelCal->fmatA[3][CHZ] = pthisAccelCal->fmatA[CHZ][3];
308 
309  // calculate in situ inverse of X^T.X
310  for (i = 0; i < 4; i++)
311  {
312  pfRows[i] = pthisAccelCal->fmatA[i];
313  }
314 
315  fmatrixAeqInvA(pfRows, iColInd, iRowInd, iPivot, 4, &ierror);
316 
317  // calculate the solution vector fvecB = inv(X^T.X).X^T.Y
318  for (i = 0; i < 4; i++)
319  {
320  pthisAccelCal->fvecB[i] = 0.0F;
321  for (j = 0; j < 4; j++)
322  {
323  pthisAccelCal->fvecB[i] += pthisAccelCal->fmatA[i][j] * pthisAccelCal->fvecA[j];
324  }
325  }
326 
327  // extract the offset vector
328  pthisAccelCal->fV[CHX] = 0.5F * pthisAccelCal->fvecB[CHX];
329  pthisAccelCal->fV[CHY] = 0.5F * pthisAccelCal->fvecB[CHY];
330  pthisAccelCal->fV[CHZ] = 0.5F * pthisAccelCal->fvecB[CHZ];
331 
332  // set ftmp to 1/W where W is the forward gain to fit the 1g sphere
333  ftmp = 1.0F / sqrtf(fabsf(pthisAccelCal->fvecB[3] + pthisAccelCal->fV[CHX] *
334  pthisAccelCal->fV[CHX] + pthisAccelCal->fV[CHY] *
335  pthisAccelCal->fV[CHY] + pthisAccelCal->fV[CHZ] *
336  pthisAccelCal->fV[CHZ]));
337 
338  // copy the inverse gain 1/W to the inverse gain matrix
339  pthisAccelCal->finvW[CHX][CHY] = pthisAccelCal->finvW[CHY][CHX] = 0.0F;
340  pthisAccelCal->finvW[CHX][CHZ] = pthisAccelCal->finvW[CHZ][CHX] = 0.0F;
341  pthisAccelCal->finvW[CHY][CHZ] = pthisAccelCal->finvW[CHZ][CHY] = 0.0F;
342  pthisAccelCal->finvW[CHX][CHX] = pthisAccelCal->finvW[CHY][CHY] = pthisAccelCal->finvW[CHZ][CHZ] = ftmp;
343 
344  return;
345 }
void fmatrixAeqInvA(float *A[], int8 iColInd[], int8 iRowInd[], int8 iPivot[], int8 isize, int8 *pierror)
function uses Gauss-Jordan elimination to compute the inverse of matrix A in situ on exit...
Definition: matrix.c:666
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fvecA[10]
scratch 10x1 vector used by calibration algorithms
float fvecB[4]
scratch 4x1 vector used by calibration algorithms
float fGsStored[MAX_ACCEL_CAL_ORIENTATIONS][3]
uncalibrated accelerometer measurements (g)
float fV[3]
offset vector (g)
int16_t iStoreFlags
denotes which measurements are present
int32_t int32
Definition: sensor_fusion.h:57
#define CHZ
#define MAX_ACCEL_CAL_ORIENTATIONS
number of stored precision accelerometer measurements
float fmatA[10][10]
scratch 10x10 matrix used by calibration algorithms
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float finvW[3][3]
inverse gain matrix

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fComputeAccelCalibration7 ( struct AccelBuffer pthisAccelBuffer,
struct AccelCalibration pthisAccelCal,
struct AccelSensor pthisAccel 
)

calculate the 7 element calibration from the available measurements

Parameters
pthisAccelBufferBuffer of measurements used as input to the accel calibration functions
pthisAccelCalAccelerometer calibration parameter structure
pthisAccelPointer to the accelerometer input/state structure

Definition at line 348 of file precisionAccelerometer.c.

Referenced by fRunAccelCalibration().

351 {
352  int32 i,
353  j,
354  m,
355  n; // loop counters
356  float det; // matrix determinant
357  float fg0; // fitted local gravity magnitude
358 
359  // zero the on and above diagonal elements of the 7x7 symmetric measurement matrix fmatA
360  for (i = 0; i < 7; i++)
361  for (j = i; j < 7; j++) pthisAccelCal->fmatA[i][j] = 0.0F;
362 
363  // last entry of vector fvecA is always 1.0 so move assignment outside the loop
364  pthisAccelCal->fvecA[6] = 1.0F;
365 
366  // loop over all orientations
367  for (i = 0; i < MAX_ACCEL_CAL_ORIENTATIONS; i++)
368  {
369  // accumulate fvecA if this entry is valid
370  if ((pthisAccelBuffer->iStoreFlags) & (1 << i))
371  {
372  // compute the remaining members of the measurement vector fvecA
373  pthisAccelCal->fvecA[0] = pthisAccelBuffer->fGsStored[i][CHX] * pthisAccelBuffer->fGsStored[i][CHX];
374  pthisAccelCal->fvecA[1] = pthisAccelBuffer->fGsStored[i][CHY] * pthisAccelBuffer->fGsStored[i][CHY];
375  pthisAccelCal->fvecA[2] = pthisAccelBuffer->fGsStored[i][CHZ] * pthisAccelBuffer->fGsStored[i][CHZ];
376  pthisAccelCal->fvecA[3] = pthisAccelBuffer->fGsStored[i][CHX];
377  pthisAccelCal->fvecA[4] = pthisAccelBuffer->fGsStored[i][CHY];
378  pthisAccelCal->fvecA[5] = pthisAccelBuffer->fGsStored[i][CHZ];
379 
380  // accumulate the on-and above-diagonal terms of fmatA=Sigma{fvecA^T * fvecA}
381  for (m = 0; m < 7; m++)
382  for (n = m; n < 7; n++)
383  pthisAccelCal->fmatA[m][n] += pthisAccelCal->fvecA[m] * pthisAccelCal->fvecA[n];
384  } // end of test for stored data
385  } // end of loop over orientations
386 
387  // copy the above diagonal elements of symmetric product matrix fmatA to below the diagonal
388  for (m = 1; m < 7; m++)
389  for (n = 0; n < m; n++)
390  pthisAccelCal->fmatA[m][n] = pthisAccelCal->fmatA[n][m];
391 
392  // set fvecA to the unsorted eigenvalues and fmatB to the unsorted normalized eigenvectors of fmatA
393  fEigenCompute10(pthisAccelCal->fmatA, pthisAccelCal->fvecA,
394  pthisAccelCal->fmatB, 7);
395 
396  // set ellipsoid matrix A from elements of the solution vector column j with smallest eigenvalue
397  j = 0;
398  for (i = 1; i < 7; i++)
399  if (pthisAccelCal->fvecA[i] < pthisAccelCal->fvecA[j]) j = i;
400 
401  // negate the entire solution vector if ellipsoid matrix has negative determinant
402  det = pthisAccelCal->fmatB[0][j] *
403  pthisAccelCal->fmatB[1][j] *
404  pthisAccelCal->fmatB[2][j];
405  if (det < 0.0F)
406  {
407  for (i = 0; i < 7; i++)
408  {
409  pthisAccelCal->fmatB[i][j] = -pthisAccelCal->fmatB[i][j];
410  }
411  }
412 
413  // compute invW and V and fitted gravity g0 from solution vector j
414  f3x3matrixAeqScalar(pthisAccelCal->finvW, 0.0F);
415  pthisAccelCal->finvW[CHX][CHX] = sqrtf(fabsf(pthisAccelCal->fmatB[0][j]));
416  pthisAccelCal->finvW[CHY][CHY] = sqrtf(fabsf(pthisAccelCal->fmatB[1][j]));
417  pthisAccelCal->finvW[CHZ][CHZ] = sqrtf(fabsf(pthisAccelCal->fmatB[2][j]));
418  pthisAccelCal->fV[CHX] = -0.5F *
419  pthisAccelCal->fmatB[3][j] /
420  pthisAccelCal->fmatB[0][j];
421  pthisAccelCal->fV[CHY] = -0.5F *
422  pthisAccelCal->fmatB[4][j] /
423  pthisAccelCal->fmatB[1][j];
424  pthisAccelCal->fV[CHZ] = -0.5F *
425  pthisAccelCal->fmatB[5][j] /
426  pthisAccelCal->fmatB[2][j];
427  fg0 = sqrtf(fabsf(pthisAccelCal->fmatB[0][j] * pthisAccelCal->fV[CHX] *
428  pthisAccelCal->fV[CHX] + pthisAccelCal->fmatB[1][j] *
429  pthisAccelCal->fV[CHY] * pthisAccelCal->fV[CHY] +
430  pthisAccelCal->fmatB[2][j] * pthisAccelCal->fV[CHZ] *
431  pthisAccelCal->fV[CHZ] - pthisAccelCal->fmatB[6][j]));
432 
433  // normalize invW to fit the 1g sphere
434  pthisAccelCal->finvW[CHX][CHX] /= fg0;
435  pthisAccelCal->finvW[CHY][CHY] /= fg0;
436  pthisAccelCal->finvW[CHZ][CHZ] /= fg0;
437 
438  return;
439 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fvecA[10]
scratch 10x1 vector used by calibration algorithms
float fGsStored[MAX_ACCEL_CAL_ORIENTATIONS][3]
uncalibrated accelerometer measurements (g)
float fV[3]
offset vector (g)
int16_t iStoreFlags
denotes which measurements are present
int32_t int32
Definition: sensor_fusion.h:57
void fEigenCompute10(float A[][10], float eigval[], float eigvec[][10], int8 n)
function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1] stored in the top left of a 10x10 array A[10][10]
Definition: matrix.c:234
#define CHZ
#define MAX_ACCEL_CAL_ORIENTATIONS
number of stored precision accelerometer measurements
float fmatA[10][10]
scratch 10x10 matrix used by calibration algorithms
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float fmatB[10][10]
scratch 10x10 matrix used by calibration algorithms
float finvW[3][3]
inverse gain matrix
void f3x3matrixAeqScalar(float A[][3], float Scalar)
function sets every entry in the 3x3 matrix A to a constant scalar
Definition: matrix.c:109

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fInitializeAccelCalibration ( struct AccelCalibration pthisAccelCal,
struct AccelBuffer pthisAccelBuffer,
volatile int8_t *  AccelCalPacketOn 
)

Initialize the accelerometer calibration functions.

Parameters
pthisAccelCalAccelerometer calibration parameter structure
pthisAccelBufferBuffer of measurements used as input to the accel calibration functions
AccelCalPacketOnUsed to coordinate calibration sample storage and communications

Definition at line 34 of file precisionAccelerometer.c.

Referenced by DecodeCommandBytes(), and initializeFusionEngine().

37 {
38  float *pFlash; // pointer into flash memory
39  int8_t i,
40  j; // loop counters
41 
42  // set flags to false to denote no precision accelerometer measurements
43  pthisAccelBuffer->iStoreFlags = 0;
44 
45  // perform one transmission of the precision calibration (using invalid value MAX_ACCEL_CAL_ORIENTATIONS for calibration only)
46  *AccelCalPacketOn = MAX_ACCEL_CAL_ORIENTATIONS;
47 
48  // check to see if the stored accelerometer calibration has been erased
49  // the standard value for erased flash is 0xFF in each byte but for portability check against 0x12345678
50  pFlash = (float *) (CALIBRATION_NVM_ADDR + ACCEL_NVM_OFFSET);
51  if (*((uint32 *) pFlash++) == 0x12345678)
52  {
53  // a precision accelerometer calibration is present in flash
54  // copy accelerometer calibration elements (21x float total 84 bytes) from flash to RAM
55  for (i = CHX; i <= CHZ; i++) pthisAccelCal->fV[i] = *(pFlash++);
56  for (i = CHX; i <= CHZ; i++)
57  for (j = CHX; j <= CHZ; j++)
58  pthisAccelCal->finvW[i][j] = *(pFlash++);
59  for (i = CHX; i <= CHZ; i++)
60  for (j = CHX; j <= CHZ; j++)
61  pthisAccelCal->fR0[i][j] = *(pFlash++);
62  }
63  else
64  {
65  // flash has been erased and no accelerometer calibration is present
66  // initialize the precision accelerometer calibration in RAM to null default
67  pthisAccelCal->fV[CHX] = pthisAccelCal->fV[CHY] = pthisAccelCal->fV[CHZ] = 0.0F;
68  f3x3matrixAeqI(pthisAccelCal->finvW);
69  f3x3matrixAeqI(pthisAccelCal->fR0);
70  }
71 
72  // set current averaging location and counter to -1 for invalid
73  pthisAccelBuffer->iStoreLocation = pthisAccelBuffer->iStoreCounter = -1;
74 
75  return;
76 }
int16_t iStoreLocation
-1 for none, 0 to 11 for the 12 storage locations
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
int16_t iStoreCounter
number of remaining iterations at FUSION_HZ to average measurement
float fV[3]
offset vector (g)
int16_t iStoreFlags
denotes which measurements are present
uint32_t uint32
Definition: sensor_fusion.h:60
#define CHZ
#define MAX_ACCEL_CAL_ORIENTATIONS
number of stored precision accelerometer measurements
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void f3x3matrixAeqI(float A[][3])
function sets the 3x3 matrix A to the identity matrix
Definition: matrix.c:45
float fR0[3][3]
forward rotation matrix for measurement 0
float finvW[3][3]
inverse gain matrix

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fInvertAccelCal ( struct AccelSensor pthisAccel,
struct AccelCalibration pthisAccelCal 
)

function maps the accelerometer data fGs (g) onto precision calibrated and de-rotated data fGc (g), iGc (counts)

Parameters
pthisAccelPointer to the accelerometer input/state structure
pthisAccelCalAccelerometer calibration parameter structure

Definition at line 130 of file precisionAccelerometer.c.

Referenced by initializeSensors().

132 {
133  // local variables
134  float ftmp[3]; // temporary array
135  int8_t i; // loop counter
136 
137  //subtract the offset vector fV (g): ftmp[]=fGs[]-V[]
138  for (i = CHX; i <= CHZ; i++)
139  ftmp[i] = pthisAccel->fGs[i] - pthisAccelCal->fV[i];
140 
141  // apply the inverse rotation correction matrix finvW: fGc=inv(W)*(fGs[]-V[])
142  for (i = CHX; i <= CHZ; i++)
143  {
144  pthisAccel->fGc[i] = pthisAccelCal->finvW[i][CHX] *
145  ftmp[CHX] +
146  pthisAccelCal->finvW[i][CHY] *
147  ftmp[CHY] +
148  pthisAccelCal->finvW[i][CHZ] *
149  ftmp[CHZ];
150  }
151 
152  // apply the inverse of the forward rotation matrix fR0: fGc=inv(R).inv(W)*(fGs[]-V[])
153  for (i = CHX; i <= CHZ; i++) ftmp[i] = pthisAccel->fGc[i];
154  for (i = CHX; i <= CHZ; i++)
155  {
156  pthisAccel->fGc[i] = pthisAccelCal->fR0[CHX][i] *
157  ftmp[CHX] +
158  pthisAccelCal->fR0[CHY][i] *
159  ftmp[CHY] +
160  pthisAccelCal->fR0[CHZ][i] *
161  ftmp[CHZ];
162  pthisAccel->iGc[i] = (int16_t) (pthisAccel->fGc[i] * pthisAccel->iCountsPerg);
163  }
164 
165  return;
166 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fV[3]
offset vector (g)
int16_t iCountsPerg
counts per g
float fGc[3]
averaged precision calibrated measurement (g)
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
int16_t iGc[3]
averaged precision calibrated measurement (counts)
float fR0[3][3]
forward rotation matrix for measurement 0
float fGs[3]
averaged measurement (g)
float finvW[3][3]
inverse gain matrix

+ Here is the caller graph for this function:

void fRunAccelCalibration ( struct AccelCalibration pthisAccelCal,
struct AccelBuffer pthisAccelBuffer,
struct AccelSensor pthisAccel 
)

function runs the precision accelerometer calibration

Parameters
pthisAccelCalAccelerometer calibration parameter structure
pthisAccelBufferBuffer of measurements used as input to the accel calibration functions
pthisAccelPointer to the accelerometer input/state structure

Definition at line 169 of file precisionAccelerometer.c.

Referenced by fUpdateAccelBuffer().

172 {
173  float fGc0[3]; // calibrated but not de-rotated measurement 0
174  uint8_t iMeasurements; // number of stored measurements
175  int8_t i; // loop counters
176 
177  // calculate how many measurements are present in the accelerometer measurement buffer
178  iMeasurements = 0;
179  for (i = 0; i < MAX_ACCEL_CAL_ORIENTATIONS; i++)
180  {
181  if (pthisAccelBuffer->iStoreFlags & (1 << i)) iMeasurements++;
182  }
183 
184  // perform the highest quality calibration possible given this number
185  if (iMeasurements >= 9)
186  {
187  // perform the 10 element calibration
188  fComputeAccelCalibration10(pthisAccelBuffer, pthisAccelCal, pthisAccel);
189  }
190  else if (iMeasurements >= 6)
191  {
192  // perform the 7 element calibration
193  fComputeAccelCalibration7(pthisAccelBuffer, pthisAccelCal, pthisAccel);
194  }
195  else if (iMeasurements >= 4)
196  {
197  // perform the 4 element calibration
198  fComputeAccelCalibration4(pthisAccelBuffer, pthisAccelCal, pthisAccel);
199  }
200 
201  // calculate the rotation correction matrix to rotate calibrated measurement 0 to flat
202  if (pthisAccelBuffer->iStoreFlags & 1)
203  {
204  // apply offset and gain calibration but not rotation to measurement 0 (flat) if present
205  // set ftmpA3x1 = invW . (fGs - fV)
206  for (i = CHX; i <= CHZ; i++)
207  fGc0[i] = pthisAccelBuffer->fGsStored[0][i] - pthisAccelCal->fV[i];
208  fVeq3x3AxV(fGc0, pthisAccelCal->finvW);
209 
210  // compute the new final rotation matrix if rotation 0 (flat) is present.
211  // multiplying by the transpose of this matrix therefore forces measurement zero to flat.
212  switch (THISCOORDSYSTEM)
213  {
214  case NED:
215  f3DOFTiltNED(pthisAccelCal->fR0, fGc0);
216  break;
217 
218  case ANDROID:
219  f3DOFTiltAndroid(pthisAccelCal->fR0, fGc0);
220  break;
221 
222  case WIN8:
223  default:
224  f3DOFTiltWin8(pthisAccelCal->fR0, fGc0);
225  break;
226  }
227  }
228 
229  return;
230 }
void fComputeAccelCalibration7(struct AccelBuffer *pthisAccelBuffer, struct AccelCalibration *pthisAccelCal, struct AccelSensor *pthisAccel)
calculate the 7 element calibration from the available measurements
void f3DOFTiltNED(float fR[][3], float fGc[])
Aerospace NED accelerometer 3DOF tilt function, computing rotation matrix fR.
void fComputeAccelCalibration4(struct AccelBuffer *pthisAccelBuffer, struct AccelCalibration *pthisAccelCal, struct AccelSensor *pthisAccel)
calculate the 4 element calibration from the available measurements
float fGsStored[MAX_ACCEL_CAL_ORIENTATIONS][3]
uncalibrated accelerometer measurements (g)
float fV[3]
offset vector (g)
#define ANDROID
identifier for Android axes and angles
int16_t iStoreFlags
denotes which measurements are present
void fComputeAccelCalibration10(struct AccelBuffer *pthisAccelBuffer, struct AccelCalibration *pthisAccelCal, struct AccelSensor *pthisAccel)
calculate the 10 element calibration from the available measurements
#define NED
identifier for NED (Aerospace) axes and angles
void fVeq3x3AxV(float V[3], float A[][3])
function multiplies the 3x1 vector V by a 3x3 matrix A
Definition: matrix.c:871
#define CHZ
#define WIN8
identifier for Windows 8 axes and angles
void f3DOFTiltAndroid(float fR[][3], float fGc[])
Android accelerometer 3DOF tilt function computing, rotation matrix fR.
#define MAX_ACCEL_CAL_ORIENTATIONS
number of stored precision accelerometer measurements
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float fR0[3][3]
forward rotation matrix for measurement 0
#define THISCOORDSYSTEM
float finvW[3][3]
inverse gain matrix
void f3DOFTiltWin8(float fR[][3], float fGc[])
Windows 8 accelerometer 3DOF tilt function computing, rotation matrix fR.

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fUpdateAccelBuffer ( struct AccelCalibration pthisAccelCal,
struct AccelBuffer pthisAccelBuffer,
struct AccelSensor pthisAccel,
volatile int8_t *  AccelCalPacketOn 
)

Update the buffer used to store samples used for accelerometer calibration.

Parameters
pthisAccelCalAccelerometer calibration parameter structure
pthisAccelBufferBuffer of measurements used as input to the accel calibration functions
pthisAccelPointer to the accelerometer input/state structure
AccelCalPacketOnUsed to coordinate calibration sample storage and communications

Definition at line 78 of file precisionAccelerometer.c.

Referenced by initializeSensors().

81 {
82  int16_t i; // loop counter
83 
84  // iStoreCounter > 0: precision measurements are still on-going
85  // iStoreCounter = 0: the precision measurement has just finished
86  // iStoreCounter = -1: no precision measurement is in progress
87  // check if a new precision measurement has started and zero sums if one has
88  if (pthisAccelBuffer->iStoreCounter == (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ))
89  {
90  for (i = CHX; i <= CHZ; i++) pthisAccelBuffer->fSumGs[i] = 0.0F;
91  }
92 
93  // accumulate sum if averaging not yet complete
94  if (pthisAccelBuffer->iStoreCounter > 0)
95  {
96  for (i = CHX; i <= CHZ; i++)
97  pthisAccelBuffer->fSumGs[i] += pthisAccel->fGs[i];
98  pthisAccelBuffer->iStoreCounter--;
99  }
100 
101  // check if the measurement accumulation is complete and, if so, store average and set packet transmit flag
102  if (pthisAccelBuffer->iStoreCounter == 0)
103  {
104  // store the measurement, set the relevant flag and decrement the counter down to -1 denoting completion
105  for (i = CHX; i <= CHZ; i++)
106  {
107  pthisAccelBuffer->fGsStored[pthisAccelBuffer->iStoreLocation][i] =
108  pthisAccelBuffer->fSumGs[i] /
109  (float) (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
110  }
111 
112  pthisAccelBuffer->iStoreFlags |=
113  (
114  1 <<
115  pthisAccelBuffer->iStoreLocation
116  );
117  pthisAccelBuffer->iStoreCounter--;
118 
119  // compute the new precision accelerometer calibration including rotation using all measurements
120  fRunAccelCalibration(pthisAccelCal, pthisAccelBuffer, pthisAccel);
121 
122  // and make one packet transmission of this measurement with the new calibration
123  *AccelCalPacketOn = pthisAccelBuffer->iStoreLocation;
124  }
125 
126  return;
127 }
int16_t iStoreLocation
-1 for none, 0 to 11 for the 12 storage locations
int16_t iStoreCounter
number of remaining iterations at FUSION_HZ to average measurement
float fGsStored[MAX_ACCEL_CAL_ORIENTATIONS][3]
uncalibrated accelerometer measurements (g)
int16_t iStoreFlags
denotes which measurements are present
void fRunAccelCalibration(struct AccelCalibration *pthisAccelCal, struct AccelBuffer *pthisAccelBuffer, struct AccelSensor *pthisAccel)
function runs the precision accelerometer calibration
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float fGs[3]
averaged measurement (g)
#define FUSION_HZ
(int) actual rate of fusion algorithm execution and sensor FIFO reads
float fSumGs[3]
averaging sum for current storage location
#define ACCEL_CAL_AVERAGING_SECS
calibration constants

+ Here is the call graph for this function:

+ Here is the caller graph for this function: